Skip to content

Physical memory access reservation for safe memory API#824

Open
sangho2 wants to merge 5 commits into
sanghle/lvbs/vmap_copyfrom
sanghle/lvbs/physlock_v2
Open

Physical memory access reservation for safe memory API#824
sangho2 wants to merge 5 commits into
sanghle/lvbs/vmap_copyfrom
sanghle/lvbs/physlock_v2

Conversation

@sangho2

@sangho2 sangho2 commented May 1, 2026

Copy link
Copy Markdown
Contributor

This PR adds support for physical memory access reservation, which is the last piece to make the VTL0/normal-world physical memory access API "safe". Now, our API is safe in the DMA/shared-memory sense:

  1. A physical address range can have up to one Rust-side accessor (i.e., no shared mapping).
  2. There is no Rust reference/slice to the physical addresses.
  3. Every read/write access is associated with "copy" to/from Rust-owned buffers.
  4. Memory copy from/to the physical addresses is based on asm (i.e., no Rust function which is undefined).

External agents (VTL0, hypervisor, peripherals, ...) can still access those physical addresses but this is out of LiteBox/Rust's control. We do have the protect method to prevent VTL0's access to them if needed.

@sangho2 sangho2 added the must-not-merge:prototype An experimental/proof-of-concept PR that must not be merged. label May 1, 2026
@sangho2 sangho2 changed the title Physical memory range ownership for safe memory read/write API Physical memory range ownership for safe memory API May 1, 2026
@sangho2 sangho2 force-pushed the sanghle/lvbs/physlock_v2 branch 2 times, most recently from 420bea6 to d0c665c Compare May 2, 2026 03:32
@sangho2 sangho2 removed the must-not-merge:prototype An experimental/proof-of-concept PR that must not be merged. label May 2, 2026
@sangho2 sangho2 marked this pull request as ready for review May 5, 2026 22:54
@sangho2 sangho2 force-pushed the sanghle/lvbs/vmap_copy branch from 8b9b1f7 to 3a833f2 Compare May 15, 2026 16:40
@sangho2 sangho2 force-pushed the sanghle/lvbs/physlock_v2 branch from 41e36c2 to a6c1102 Compare May 15, 2026 16:51
@sangho2 sangho2 added the must-not-merge:blocked-on-other-changes Other changes/PRs to be handled first. Label not needed for non-main changes. label May 15, 2026
@sangho2 sangho2 force-pushed the sanghle/lvbs/physlock_v2 branch from 2473ace to 27bb1dd Compare May 15, 2026 20:24
@sangho2 sangho2 force-pushed the sanghle/lvbs/vmap_copy branch from 24fcce1 to 3dc8650 Compare May 21, 2026 20:28
@sangho2 sangho2 force-pushed the sanghle/lvbs/vmap_copy branch from 24e1d87 to 9b0f0f0 Compare May 29, 2026 02:48
@sangho2 sangho2 force-pushed the sanghle/lvbs/physlock_v2 branch from 6dbe423 to f6d2dc0 Compare May 29, 2026 04:26
@sangho2 sangho2 removed the must-not-merge:blocked-on-other-changes Other changes/PRs to be handled first. Label not needed for non-main changes. label May 29, 2026
@sangho2 sangho2 marked this pull request as draft June 2, 2026 16:31
@sangho2 sangho2 changed the title Physical memory range ownership for safe memory API Physical memory access reservation for safe memory API Jun 2, 2026
@sangho2 sangho2 marked this pull request as ready for review June 2, 2026 18:10
@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown

ℹ️ Note: This semver check was run against the sanghle/lvbs/vmap_copy branch, not main or ulitebox.

🤖 SemverChecks 🤖 ⚠️ Potential breaking API changes detected ⚠️

Click for details
--- failure derive_trait_impl_removed: built-in derived trait no longer implemented ---

Description:
A public type has stopped deriving one or more traits. This can break downstream code that depends on those types implementing those traits.
        ref: https://doc.rust-lang.org/reference/attributes/derive.html#derive
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.48.0/src/lints/derive_trait_impl_removed.ron

Failed in:
  type PhysConstPtr no longer derives Clone, in /home/runner/work/litebox/litebox/litebox_common_linux/src/physical_pointers.rs:482
  type PhysMutPtr no longer derives Clone, in /home/runner/work/litebox/litebox/litebox_common_linux/src/physical_pointers.rs:91

--- failure struct_missing: pub struct removed or renamed ---

Description:
A publicly-visible struct cannot be imported by its prior path. A `pub use` may have been removed, or the struct itself may have been renamed or removed entirely.
        ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.48.0/src/lints/struct_missing.ron

Failed in:
  struct litebox_common_linux::vmap::PhysPageMapInfo, previously in file /home/runner/work/litebox/litebox/target/semver-checks/git-sanghle_lvbs_vmap_copy/acd6ae561116135b6915cf113a535d2c2e02cfc9/litebox_common_linux/src/vmap.rs:111

--- failure trait_associated_type_added: non-sealed public trait added associated type without default value ---

Description:
A non-sealed trait has gained an associated type without a default value, which breaks downstream implementations of the trait
        ref: https://doc.rust-lang.org/cargo/reference/semver.html#trait-new-item-no-default
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.48.0/src/lints/trait_associated_type_added.ron

Failed in:
  trait associated type litebox_common_linux::vmap::VmapManager::MapInfo in file /home/runner/work/litebox/litebox/litebox_common_linux/src/vmap.rs:33

--- failure trait_unsafe_added: pub trait became unsafe ---

Description:
A publicly-visible trait became `unsafe`, so implementing it now requires an `unsafe impl` block.
        ref: https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#implementing-an-unsafe-trait
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.48.0/src/lints/trait_unsafe_added.ron

Failed in:
  trait litebox_common_linux::vmap::VmapManager in file /home/runner/work/litebox/litebox/litebox_common_linux/src/vmap.rs:28

@wdcui

wdcui commented Jun 12, 2026

Copy link
Copy Markdown
Member

@CvvT I think we should take a look at this PR as well. Thanks!

@wdcui wdcui left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left some comments below. I'm confident about my review because this PR has a lot of subtlties, so I didn't approve it and asked Weiteng to take a look at it as well.

exec_ranges: Option<&[Range<PhysAddr>]>,
) -> Result<*mut u8, MapToError<Size4KiB>> {
self.map_phys_frame_range_with(frame_range, flags, exec_ranges, M::pa_to_va_direct)
self.map_phys_frame_range_with(frame_range, flags, exec_ranges, M::pa_to_va_direct, true)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this function need rollback but map_phys_frame_range doesn't

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All these rollback stuffs are some kinds of patching. It doesn't try to modify existing logic as much as possible. Technically, most of these mapping failures are critical bugs and rollbacks are just best-effort mitigation.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems that it is better not to deal with rollback in this PR.

/// We might need to emulate these functions' behaviors using virtual addresses for development or
/// testing, or use a kernel module to provide this functionality (if needed).
impl<const ALIGN: usize> VmapManager<ALIGN> for LinuxUserland {}
unsafe impl<const ALIGN: usize> VmapManager<ALIGN> for LinuxUserland {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this one become unsafe?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This trait has some safety requirements which cannot be easily enforced by Rust code.

/// requested physical pages in order, that the returned [`Self::MapInfo`] owns the mapping and any
/// access reservation needed for the mapping lifetime, and that [`Self::vunmap`] does not release
/// that reservation unless the mapping has been invalidated or safely retained in the returned
/// [`Self::MapInfo`]. Implementors must also ensure [`Self::validate_unowned`] rejects physical

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: the last sentence needs some fix?

PhysFrame::<Size4KiB>::containing_address(frame.start_address()),
));
}
if rollback_on_error {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the branch on line 583, there is no rollback?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point (line 583), everything is pretty blur because something unexpected exists in the page table (a critical bug). We can still rollback some partial mappings, though. Let me do this.

#[error("Page-table frame allocation failed (out of memory)")]
FrameAllocationFailed,
#[error("Physical address range starting at {0:#x} is already locked")]
PhysicalAddressRangeLocked(usize),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error is not properly converted in litebox_common_optee/src/lib.rs:2289?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EBusy might be better for this error.

Comment thread litebox_common_linux/src/physical_pointers.rs
Comment thread litebox_common_linux/src/physical_pointers.rs
Comment on lines +168 to +174
let mut inner = PHYS_RANGE_RESERVATIONS.lock();
for range in &self.ranges {
if let Some(index) = inner.entries.iter().position(|entry| entry == range) {
inner.entries.swap_remove(index);
}
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related to my early comment: the leak of PhysPageMapInfo is to prevent calling this Drop. Should we make it explicit, e.g., PhyMutPtr requires implementing remove_range? Then we don't need to leak memory on the failure path.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does. PhysPtr's unmap (drop) calls page table's unmap eventually. This leak is mostly about page-table-level unmap failure, and we cannot avoid memory leak at this point.

Comment on lines +436 to 439
// SAFETY: The platform is expected to handle unmapping safely. Drop cannot
// report errors, so a failed unmap leaves map_info restored in the owner and
// is only reported by debug assertion.
let result = unsafe { self.owner.unmap() };

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MappedGuard's Drop calls PhyMutPtr's unmap, and when the PhyMutPtr drops, it also calls unmap?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes. PhysPtr's unmap -> Vmap's vunmap -> page table's unmap.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants